package bookhive.catalog;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

import bookhive.datasource.DataSource;
import bookhive.datastructures.datasource.DataSourceItem;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.Element;
import net.jxta.document.MimeMediaType;
import net.jxta.document.StructuredDocumentFactory;
import net.jxta.document.XMLDocument;
import net.jxta.endpoint.InputStreamMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.peer.PeerID;
import net.jxta.pipe.OutputPipe;
import net.jxta.pipe.PipeService;
import net.jxta.protocol.PipeAdvertisement;

public class CatalogRequestHandler extends Thread {

	private DataSource dataSource = null;

	private Message msg = null;

	private PipeService pipes = null;

	private MimeMediaType XMLMIMETPYE = new MimeMediaType("text/xml");

	private PeerID peerID = null;

	public CatalogRequestHandler(DataSource ds, Message m, PipeService p,
			PeerID pID) {
		dataSource = ds;
		msg = m;
		pipes = p;
		peerID = pID;
	}

	@Override
	public void run() {
		XMLDocument responseDocument = (XMLDocument) StructuredDocumentFactory
				.newStructuredDocument(XMLMIMETPYE, "Response");

		PipeAdvertisement requestorPipeAdv = null;
		MessageElement requestorPipeAdvEl = msg.getMessageElement("Requestor");
		try {
			XMLDocument requestorDocument = (XMLDocument) StructuredDocumentFactory
					.newStructuredDocument(requestorPipeAdvEl);
			requestorPipeAdv = (PipeAdvertisement) AdvertisementFactory
					.newAdvertisement(requestorDocument);
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}

		MessageElement request = msg.getMessageElement("Request");
		try {
			XMLDocument requestDocument = (XMLDocument) StructuredDocumentFactory
					.newStructuredDocument(request);

			Enumeration queryElementEnum = requestDocument.getChildren("Query");
			while (queryElementEnum.hasMoreElements()) {
				Element queryEl = (Element) queryElementEnum.nextElement();
				CatalogQuery cquery = new CatalogQuery(queryEl);
				Vector<DataSourceItem> records = new Vector<DataSourceItem>();

				synchronized (dataSource) {

					if (cquery.getQueryType().equals("hash")) {
						records.addAll(dataSource.sendHashQuery(cquery
								.getQueryData()));
						System.out.println(cquery.getQueryData());
					} else if (cquery.getQueryType().equals("data")) {
						records.addAll(dataSource.sendDataQuery(cquery
								.getQueryData()));
					} else if (cquery.getQueryType().equals("update")) {
						dataSource.sendUpdateQuery(cquery.getQueryData());
						return;
					} else if (cquery.getQueryType().equals("redund")) {
						dataSource.sendRedundQuery(cquery.getQueryData());
						return;
					} else
						return;
				}

				if (records.size() > 500 || records.isEmpty())
					return;

				Element peerNameEl = responseDocument.createElement(
						"CatalogPeerID", peerID.toString());
				responseDocument.appendChild(peerNameEl);
				Element resultEl = responseDocument.createElement("Result");
				responseDocument.appendChild(resultEl);
				Element queryTypeEl = responseDocument.createElement(
						"QueryType", cquery.getQueryType());
				resultEl.appendChild(queryTypeEl);
				Element queryDataEl = responseDocument.createElement(
						"QueryData", cquery.getQueryData());
				resultEl.appendChild(queryDataEl);
				Element recordCountEl = responseDocument.createElement(
						"RecordCount", String.valueOf(records.size()));
				resultEl.appendChild(recordCountEl);
				Element recordsEl = responseDocument.createElement("Records");
				resultEl.appendChild(recordsEl);

				if (records != null) {
					Iterator<DataSourceItem> recordIter = records.iterator();
					while (recordIter.hasNext()) {
						DataSourceItem rec = recordIter.next();
						rec.addToParentElement(recordsEl, responseDocument);
					}

				}
			}

		} catch (IOException e) {
			e.printStackTrace();
			return;
		}
		sendResponse(requestorPipeAdv, responseDocument);

	}

	private void sendResponse(PipeAdvertisement requestorPipeAdv,
			XMLDocument responseDocument) {

		try {
			InputStreamMessageElement isme = new InputStreamMessageElement(
					"Response", XMLMIMETPYE, responseDocument.getStream(), null);
			Message m = new Message();
			m.addMessageElement(isme);
			OutputPipe op = pipes.createOutputPipe(requestorPipeAdv, 60000);
			op.send(m);

		} catch (Exception e) {
			System.out.println("Exception: " + e.getMessage());
		}

	}

}

class CatalogQuery {

	private String queryType;

	private String queryData;

	public CatalogQuery(Element queryEl) {
		Enumeration queryParamsEnum = queryEl.getChildren();
		while (queryParamsEnum.hasMoreElements()) {
			Element queryParam = (Element) queryParamsEnum.nextElement();
			if (queryParam.getKey().toString().equals("QueryType"))
				queryType = queryParam.getValue().toString();
			else if (queryParam.getKey().toString().equals("QueryData")) {
				queryData = queryParam.getValue().toString();
			}
		}
	}

	public String getQueryData() {
		return queryData;
	}

	public String getQueryType() {
		return queryType;
	}

}
